package com.jgp.workflow.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jgp.common.pojo.TreeBean;
import com.jgp.common.utils.JGPUtil;
import com.jgp.security.config.SecUserAdapter;
import com.jgp.security.pojo.UserInfo;
import com.jgp.security.secmodel.SecInstitution;
import com.jgp.security.secmodel.SecRole;
import com.jgp.security.secmodel.SecUser;
import com.jgp.security.service.SecInstitutionService;
import com.jgp.security.service.SecRoleService;
import com.jgp.security.service.SecUserService;
import com.jgp.sys.ui.Pager;
import com.jgp.workflow.exception.WorkflowErrorCode;
import com.jgp.workflow.exception.WorkflowException;
import com.jgp.workflow.mapper.TaskMapper;
import com.jgp.workflow.pojo.*;
import com.jgp.workflow.service.BackService;
import com.jgp.workflow.service.ProcessService;
import com.jgp.workflow.utils.AddMultiInstanceExecutionCmd;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.*;
import org.activiti.engine.history.*;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.cmd.AbstractCustomSqlExecution;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.*;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.*;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2018/11/26
 */
@Service
public class ProcessServiceImpl implements ProcessService {

    private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private FormService formService;

    @Autowired
    private ManagementService managementService;

    @Lazy
    @Autowired
    private SecUserService userService;

    @Lazy
    @Autowired
    private SecUserAdapter userAdapter;

    @Lazy
    @Autowired
    private SecRoleService roleService;

    @Lazy
    @Autowired
    private SecInstitutionService institutionService;

    @Lazy
    @Autowired
    private BackService backService;

    @Transactional
    @Override
    public Boolean publishProcess(String modelId) throws IOException {

        byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
        JsonNode jsonNode = new ObjectMapper().readTree(modelEditorSource);
        BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
        BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(jsonNode);

        Process process = bpmnModel.getMainProcess();
        if (Objects.isNull(process)) {
            logger.error("没有创建流程图");
            return false;
        }

        String fileName = process.getName() + LocalDateTime.now() + ".bpmn20.xml";
        byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(xmlBytes);

        DeploymentBuilder builder = repositoryService.createDeployment();
        Model model = repositoryService.getModel(modelId);
        builder.addInputStream(fileName, inputStream);
        builder.tenantId(model.getTenantId());
        builder.name(model.getName());
        builder.category(model.getCategory());
        Deployment deployment = builder.deploy();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
        model.setDeploymentId(processDefinition.getDeploymentId());
        repositoryService.saveModel(model);

        return true;
    }


    /**
     * 启动流程
     *
     * @param tenantId    业务系统ID
     * @param defKey      流程定义key
     * @param businessKey 业务主键
     * @param variables   全局变量
     * @return
     * @throws WorkflowException
     */
    @Transactional
    @Override
    public Map<String, Object> start(String userId, String tenantId, String defKey, String businessKey, Map<String, Object> variables) {
        Assert.notNull(userId, "用户ID不能为空！");
        Assert.notNull(tenantId, "系统ID不能为空！");
        Assert.notNull(defKey, "流程定义key不能为空！");
        Assert.notNull(businessKey, "业务key不能为空！");
        identityService.setAuthenticatedUserId(userId);
        RuntimeService runtimeService = processEngine.getRuntimeService();
        Long count = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, Long>(TaskMapper.class) {
            @Override
            public Long execute(TaskMapper taskMapper) {
                return taskMapper.queryAllProcCount();
            }
        });
        String sn = (count+1L)+"";
        Long exitOrNot = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, Long>(TaskMapper.class) {
            @Override
            public Long execute(TaskMapper taskMapper) {
                return taskMapper.queryExist(sn);
            }
        });
        if(exitOrNot > 0){
            count++;
        }
        ProcessInstance instance;

        if (Objects.isNull(variables)) {
            instance = runtimeService.startProcessInstanceByKeyAndTenantId((count + 1) + "", defKey, businessKey, tenantId);
        } else {
            instance = runtimeService.startProcessInstanceByKeyAndTenantId((count + 1) + "", defKey, businessKey, variables, tenantId);
        }

        runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), ((ExecutionEntity) instance).getProcessDefinition().getName());
        String remark = "用户:" + userId + ":启动并发起了" + ((ExecutionEntity) instance).getProcessDefinition().getName();
        logger.info("流程梳理所属流程定义id：" + instance.getProcessDefinitionId());
        logger.info("流程实例的id：" + instance.getProcessInstanceId());
        logger.info("流程实例的执行id：" + instance.getId());
        logger.info("流程当前的活动（结点）id：" + instance.getActivityId());
        logger.info("业务标识：" + instance.getBusinessKey());
        logger.info(remark);
        Map<String, Object> result = new HashMap<>();
        result.put("procId", instance.getId());
        return result;
    }

    @Override
    public List<ViewProcessTask> getActiveTask(String procId) {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procId).active().list();
        return Objects.isNull(tasks) && tasks.size() > 0 ? null : tasks.stream().map(task -> taskToViewTask(processInstance, task, null))
                                                                       .collect(Collectors.toList());
    }

    @Override
    public ViewProcessTask getTaskByProcIdAndTaskDefKey(String procId, String taskDefKey) {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        Task task = taskService.createTaskQuery().processInstanceId(procId).taskDefinitionKey(taskDefKey).singleResult();
        return taskToViewTask(processInstance, task, null);
    }

    @Override
    public List<ViewTaskDefinition> getNextTaskDefinition(String procId) {
        Task task = taskService.createTaskQuery().processInstanceId(procId).active().singleResult();
        String excId = task.getExecutionId();
        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(excId).singleResult();
        String activeId = execution.getActivityId();
        return getNextTaskDefinition(procId, activeId);
    }

    private List<ViewTaskDefinition> getNextTaskDefinition(String procId, String activeId) {
        List<ViewTaskDefinition> viewTaskDefinitions = new ArrayList<>();

        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();

        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

        if (processDefinition != null) {
            ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) processDefinition;
            /*TaskEntity task = (TaskEntity)taskService.createTaskQuery().processInstanceId(procId).active().singleResult();
            task.getExecution().getCurrentActivityId()*/
            ActivityImpl activityImpl = processDefinitionEntity.findActivity(activeId);//当前节点
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitions) {
                PvmActivity pa = pvmTransition.getDestination();//获取所有的终点节点
                if ("exclusiveGateway".equals(pa.getProperty("type"))) {
                    viewTaskDefinitions.addAll(getNextTaskDefinition(procId, pa.getId()));
                } else if ("userTask".equals(pa.getProperty("type"))) {
                    ActivityBehavior behavior = ((ActivityImpl) pa).getActivityBehavior();
                    TaskDefinition definition;
                    if (behavior.getClass().isAssignableFrom(ParallelMultiInstanceBehavior.class)) {
                        definition = ((UserTaskActivityBehavior) ((ParallelMultiInstanceBehavior) ((ActivityImpl) pa).getActivityBehavior())
                                .getInnerActivityBehavior()).getTaskDefinition();
                    } else if (behavior.getClass().isAssignableFrom(SequentialMultiInstanceBehavior.class)) {
                        definition = ((UserTaskActivityBehavior) ((SequentialMultiInstanceBehavior) ((ActivityImpl) pa).getActivityBehavior())
                                .getInnerActivityBehavior()).getTaskDefinition();
                    } else {
                        definition = ((UserTaskActivityBehavior) ((ActivityImpl) pa).getActivityBehavior()).getTaskDefinition();
                    }
                    ViewTaskDefinition taskDefinition = new ViewTaskDefinition();
                    taskDefinition.setName(definition.getNameExpression().getExpressionText());
                    taskDefinition.setTaskDefKey(definition.getKey());
                    viewTaskDefinitions.add(taskDefinition);
                }
            }
        }
        return viewTaskDefinitions;
    }

    @Override
    public String getTaskLastAssignee(String procId, String taskId) {
        String taskDefKey = historyService.createHistoricTaskInstanceQuery().taskId(taskId).list().get(0).getTaskDefinitionKey();
        return historyService.createHistoricTaskInstanceQuery().processInstanceId(procId).taskDefinitionKey(taskDefKey).finished()
                             .orderByHistoricTaskInstanceEndTime().desc().list().get(0).getAssignee();
    }

    @Override
    public void setAssignee(String taskId, String userId) {
        //taskService.setAssignee(taskId,userId);
        //List<HistoricIdentityLink> ids = historyService.get(taskId).stream().sorted();
        taskService.addUserIdentityLink(taskId, userId, IdentityLinkType.ASSIGNEE);
    }

    @Override
    public void addMultiInstanceExecution(String taskId, List<String> assigneeList) {
        managementService.executeCommand(new AddMultiInstanceExecutionCmd(taskId, assigneeList));
    }

    @Override
    public void setCandidate(String taskId, String... userIds) {
        for (String userId : userIds) {
            taskService.addUserIdentityLink(taskId, userId, IdentityLinkType.CANDIDATE);
        }
    }

    @Override
    public void grantTo(String taskId, String owner, String assignee) {
        taskService.setOwner(taskId, owner);
        taskService.setAssignee(taskId, assignee);
    }

    /**
     * @param procId    流程实例Id
     * @param taskId    任务Id
     * @param remark    备注
     * @param variables 【全局】变量 作用域整个流程实例
     * @throws WorkflowException
     */
    @Transactional
    @Override
    public void completeWithGlobalVariables(String userId, String procId, String taskId, Map<String, Object> variables, String remark) throws WorkflowException {
        complete(userId, procId, taskId, remark, variables, false);
    }

    /**
     * @param procId    流程实例Id
     * @param taskId    任务Id
     * @param remark    备注
     * @param variables 【局部】变量 作用域当前任务节点
     * @throws WorkflowException
     */
    @Transactional
    @Override
    public void completeWithLocalVariables(String userId, String procId, String taskId, Map<String, Object> variables, String remark) throws WorkflowException {
        complete(userId, procId, taskId, remark, variables, true);
    }

    /**
     * @param procId 流程实例Id
     * @param taskId 任务Id
     * @param remark 备注
     * @throws WorkflowException
     */
    @Transactional
    @Override
    public void complete(String userId, String procId, String taskId, String remark) throws WorkflowException {
        complete(userId, procId, taskId, remark, null, null);
    }

    @Transactional
    @Override
    public void backTarget(String userId, String procId, String taskId, String targetTaskKey, String remark) {
        try {
            this.taskService.setAssignee(taskId, userId);
            backService.turnBackNew(procId, taskId, targetTaskKey, remark, userId);
        } catch (Exception e) {
            throw new RuntimeException("退回失败！！");
        }
    }

    @Transactional
    @Override
    public void backTargetAndSetCandidate(String userId, String procId, String taskId, String targetTaskKey, String remark, List<TargetPerson> targetPersons) {
        try {
            backService.turnBackNew(procId, taskId, targetTaskKey, remark, userId, targetPersons);
        } catch (Exception e) {
            throw new RuntimeException("退回失败！！");
        }
    }
    
    /*private ActivityImpl nextActivity(ActivityImpl activity) {
        List<PvmTransition> outGoings = activity.getOutgoingTransitions();
        if (CollectionUtils.isNotEmpty(outGoings)) {
            PvmTransition pvmTransition = outGoings.get(0);
            return (ActivityImpl) pvmTransition.getDestination();
        }
        return null;
    }
    
    private ActivityImpl prevActivity(ActivityImpl activity) {
        List<PvmTransition> inGoings = activity.getIncomingTransitions();
        if (CollectionUtils.isNotEmpty(inGoings)) {
            PvmTransition pvmTransition = inGoings.get(0);
            return (ActivityImpl) pvmTransition.getSource();
        }
        return null;
    }*/

    @Override
    public InputStream queryProcessStatePic(String processInsId) {
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInsId).singleResult();
        BpmnModel model = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        List<String> highLightedActivities = new ArrayList<>();


        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();
        defaultProcessDiagramGenerator.generateDiagram(model, "png", highLightedActivities);


        return null;//new ByteArrayInputStream(out.toByteArray());
    }


    @Override
    public InputStream queryProcessPic(String defKey) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(defKey).latestVersion()
                                                               .singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
        InputStream in = processEngineConfiguration.getProcessDiagramGenerator()
                                                   .generateDiagram(bpmnModel, "png", new ArrayList<>(0), new ArrayList<>(0), "宋体", "宋体", "宋体", null,
                                                                    1.0
                                                   );
        return in;
    }

    @Override
    public List<ViewProcessTask> queryCompletedTask(String userId, Pager pager) {
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().finished().or().taskAssignee(userId).taskOwner(userId)
                                                        .endOr();

        Long count = query.count();
        pager.setTotalCount(count);

        List<HistoricTaskInstance> tasks = query.orderByHistoricTaskInstanceEndTime().desc()
                                                .listPage((pager.getCurrent() - 1) * pager.getPageSize(), pager.getPageSize());
        if (Objects.isNull(tasks) || tasks.size() == 0) return null;
        Set<String> procIds = tasks.stream().map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toSet());

        Map<String, Object> variableMap = new HashMap<>();

        List<ProcVar> procVars = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<ProcVar>>(TaskMapper.class) {
            @Override
            public List<ProcVar> execute(TaskMapper taskMapper) {
                return taskMapper.getProcVar(procIds, "orderContent");
            }
        });

        procVars.forEach(procVar -> {
            if (procVar.getType().equals("string")) {
                variableMap.put(procVar.getProcId(), procVar.getTextValue());
            }
        });


        if (Objects.isNull(procIds) || procIds.size() == 0) return null;
        List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery().processInstanceIds(procIds).list();

        List<String> userIds = tasks.stream().map(HistoricTaskInstance::getAssignee).collect(Collectors.toList());
        Map<String, HistoricProcessInstance> procMap = new HashMap<>();
        processInstances.forEach(processIns -> {
            procMap.put(processIns.getId(), processIns);
            userIds.add(processIns.getStartUserId());
        });
        
        
        /*List<Task> activeTasks = taskService.createTaskQuery().active().processInstanceIdIn(new ArrayList<>(procIds)).list();
        
        Map<String, Task> activeTaskMap = activeTasks.stream().collect(Collectors.toMap(Task::getId, task -> task));
        List<String> nextUserIds = activeTasks.stream().filter(activeTask -> StringUtils.isNotBlank(activeTask.getAssignee())).map(Task::getAssignee)
                                              .collect(Collectors.toList());
        userIds.addAll(nextUserIds);*/
        Map<String, SecUser> userMap = queryUsersForMap(userIds);


        Map<String, List<TaskComment>> taskCommentMap = taskCommentMap(tasks);
        List<ViewProcessTask> vtasks = tasks.stream().map(taskInstance -> {
            HistoricProcessInstance processInstance = procMap.get(taskInstance.getProcessInstanceId());
            if (Objects.isNull(processInstance)) return null;
            ViewProcessTask task = hisTaskToViewTask(processInstance, taskInstance, userMap);
            List<TaskComment> msgs = taskCommentMap.get(task.getTaskId());

            if (Objects.nonNull(msgs)) {
                task.setComments(msgs);
            }

            Object orderContent = variableMap.get(taskInstance.getProcessInstanceId());
            if (Objects.nonNull(orderContent)) {
                task.setOrderContent(orderContent);
            }
            /*Task activeTask = activeTaskMap.get(taskInstance.getId());
            if (Objects.nonNull(activeTask) && StringUtils.isNotBlank(activeTask.getAssignee())) {
                task.setNextAssignee(activeTask.getAssignee());
                SecUser user = userMap.get(activeTask.getAssignee());
                task.setNextAssigneeName(StringUtils.isBlank(user.getRealName()) ? user.getUsername() : user.getRealName());
            }*/
            return task;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        return vtasks;
    }

    private Map<String, List<TaskComment>> taskCommentMap(List<HistoricTaskInstance> tasks) {
        List<String> taskIds = tasks.stream().map(HistoricTaskInstance::getId).collect(Collectors.toList());
        List<TaskComment> comments = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<TaskComment>>(TaskMapper.class) {
                    @Override
                    public List<TaskComment> execute(TaskMapper taskMapper) {
                        return taskMapper.queryTaskComments(taskIds);
                    }
                });
        Map<String, List<TaskComment>> taskCommentMap = new HashMap<>();
        for (TaskComment comment : comments) {
            String taskId = comment.getTaskId();
            if (Objects.isNull(taskCommentMap.get(taskId))) {
                taskCommentMap.put(taskId, new ArrayList<>());
            }
            taskCommentMap.get(taskId).add(comment);
        }

        return taskCommentMap;
    }

    @Override
    public List<ViewProcessTask> queryNotHandledTask(String userId, String sn, String procName, String taskName, List<String> groupIds,
                                                     List<String> institutionIds, Pager pager) {

        TaskQuery query = taskService.createTaskQuery().active();

        if (StringUtils.isNotBlank(sn)) {
            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().unfinished().processInstanceSn(sn)
                                                                    .singleResult();
            if (Objects.isNull(processInstance)) {
                return null;
            }
            query.processInstanceId(processInstance.getId());
        }

        if (StringUtils.isNotBlank(procName)) {
            query.processDefinitionNameLike("%" + procName + "%");
        }

        if (StringUtils.isNotBlank(taskName)) {
            query.taskNameLikeIgnoreCase("%" + taskName + "%");
        }

        if (CollectionUtils.isNotEmpty(institutionIds)) {
            List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery().unfinished()
                                                                           .processInstanceInstitutionIds(
                                                                                   institutionIds.stream().collect(Collectors.toSet())).list();
            if (Objects.nonNull(processInstances) && processInstances.size() > 0) {
                List<String> procIds = processInstances.stream().map(HistoricProcessInstance::getId).distinct().collect(Collectors.toList());
                if (procIds.size() > 0) {
                    query.processInstanceIdIn(procIds);
                }
            }
        }

        if (Objects.nonNull(groupIds) && groupIds.size() > 0) {
            query.or().taskAssignee(userId).taskCandidateUser(userId).taskCandidateGroupIn(groupIds).endOr();
        } else {
            query.or().taskCandidateUser(userId).taskAssignee(userId).endOr();
        }

        Long count = query.count();
        pager.setTotalCount(count);

        List<Task> tasks = query.orderByTaskPriority().desc().orderByTaskCreateTime().desc()
                                .listPage((pager.getCurrent() - 1) * pager.getPageSize(), pager.getPageSize());

        if (Objects.isNull(tasks) || tasks.size() == 0) return null;
        Set<String> procIds = tasks.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
        if (Objects.isNull(procIds) || procIds.size() == 0) return null;
        List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery().unfinished().processInstanceIds(procIds)
                                                                       .list();

        List<String> userIds = tasks.stream().map(Task::getAssignee).collect(Collectors.toList());

        Map<String, HistoricProcessInstance> procMap = new HashMap<>();

        processInstances.forEach(processIns -> {
            procMap.put(processIns.getId(), processIns);
            userIds.add(processIns.getStartUserId());
        });

        Map<String, SecUser> userMap = queryUsersForMap(userIds);

        // List<String> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        
       /* List<String> importantTaskIds = null;
        if (Objects.nonNull(taskIds) && taskIds.size() > 0) {
            QueryFilterList filters1 = new QueryFilterList();
            filters1.addFilter("taskId", Operator.in, taskIds);
            importantTaskIds = repository.read(filters1).stream().map(ImportantTask::getTaskId).collect(Collectors.toList());
        }
        
        List<String> importantProcIds = null;
        if (Objects.nonNull(procIds) && procIds.size() > 0) {
            QueryFilterList filters2 = new QueryFilterList();
            filters2.addFilter("procId", Operator.in, new ArrayList<>(procIds));
            importantProcIds = repository.read(filters2).stream().map(ImportantTask::getProcId).collect(Collectors.toList());
        }*/
        
        /*List<String> finalImportantTaskIds = importantTaskIds;
        List<String> finalImportantProcIds = importantProcIds;*/

        Map<String, Object> variableMap = new HashMap<>();

        List<ProcVar> procVars = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<ProcVar>>(TaskMapper.class) {
            @Override
            public List<ProcVar> execute(TaskMapper taskMapper) {
                return taskMapper.getProcVar(procIds, "orderContent");
            }
        });

        procVars.forEach(procVar -> {
            if (procVar.getType().equals("string")) {
                variableMap.put(procVar.getProcId(), procVar.getTextValue());
            }
        });

        return tasks.stream().map(taskInstance -> {
            HistoricProcessInstance processInstance = procMap.get(taskInstance.getProcessInstanceId());
            if (Objects.isNull(processInstance)) return null;

            ViewProcessTask task = taskToViewTask(processInstance, taskInstance, userMap);
            
           /* if (finalImportantTaskIds.contains(task.getTaskId()) || finalImportantProcIds.contains(taskInstance.getProcessInstanceId())) {
                task.setImportant(true);
            } else {
                task.setImportant(false);
            }*/

            Object orderContent = variableMap.get(processInstance.getId());

            if (Objects.nonNull(orderContent)) {
                task.setOrderContent(orderContent);
            }

            return task;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    private Map<String, SecUser> queryUsersForMap(List<String> assigneeIds) {
        List<SecUser> users = userService.query(assigneeIds);
        Map<String, SecUser> assignees = new HashMap<>();
        users.forEach(adminUser -> {
            assignees.put(adminUser.getId(), adminUser);
        });
        return assignees;
    }

    @Override
    public List<ViewProcessTask> queryApplyButNotPass(String userId, Pager pager) {
        Long count = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, Long>(TaskMapper.class) {
            @Override
            public Long execute(TaskMapper taskMapper) {
                return taskMapper.countApplyButNotPass(userId);
            }
        });
        pager.setTotalCount(count);
        List<ViewProcessTask> list = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<ViewProcessTask>>(TaskMapper.class) {
                    @Override
                    public List<ViewProcessTask> execute(TaskMapper taskMapper) {
                        int pageStart = (pager.getCurrent() - 1) * pager.getPageSize();
                        int pageOffset = pager.getPageSize();
                        return taskMapper.queryApplyButNotPass(userId, pageStart, pageOffset);
                    }
                });
        List<String> userIds = list.stream().map(ViewProcessTask::getStartUser).collect(Collectors.toList());
        userIds.addAll(list.stream().map(ViewProcessTask::getAssignee).collect(Collectors.toList()));
        userIds = userIds.stream().filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        Map<String, SecUser> userMap = queryUsersForMap(userIds);
        list.forEach(task -> {
            SecUser startUser = userMap.get(task.getStartUser());
            SecUser assignee = userMap.get(task.getAssignee());
            if (Objects.nonNull(startUser)) {
                task.setStartUserName(personName(startUser));
            }
            if (Objects.nonNull(assignee)) {
                task.setAssigneeName(personName(assignee));
            }
        });
        return list;
    }

    @Override
    public ViewProcessTask queryNotHandledTaskByTaskId(String taskId) {
        Task task = taskService.createTaskQuery().active().taskId(taskId).singleResult();
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().unfinished()
                                                                .processInstanceId(task.getProcessInstanceId()).singleResult();
        List<String> userIds = new ArrayList<>();
        userIds.add(task.getAssignee());
        userIds.add(processInstance.getStartUserId());
        Map<String, SecUser> userMap = queryUsersForMap(userIds);
        return taskToViewTask(processInstance, task, userMap);
    }

    @Override
    public List<ViewProcessTask> queryProcessTaskFlowed(String procId, Pager pager) {
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().finished().processInstanceId(procId);
        Long count = query.count();
        pager.setTotalCount(count);

//        List<HistoricTaskInstance> tasks = query.orderByTaskCreateTime().desc()
//                                                .listPage((pager.getCurrent() - 1) * pager.getPageSize(), pager.getPageSize());
        List<HistoricTaskInstance> tasks = query.orderByTaskCreateTime().desc().list();

        Set<String> procIds = tasks.stream().map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toSet());
        if (Objects.isNull(procIds) || procIds.size() == 0) return null;
        List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery().processInstanceIds(procIds).list();


        List<String> userIds = tasks.stream().map(HistoricTaskInstance::getAssignee).collect(Collectors.toList());
        Map<String, HistoricProcessInstance> procMap = new HashMap<>();
        processInstances.forEach(processIns -> {
            procMap.put(processIns.getId(), processIns);
            userIds.add(processIns.getStartUserId());
        });
        Map<String, List<TaskComment>> taskCommentMap = taskCommentMap(tasks);


        Set<Long> roleIds = new HashSet<>();
        Set<Long> orgIds = new HashSet<>();

        List<Task> activeTasks = taskService.createTaskQuery().active().processInstanceIdIn(new ArrayList<>(procIds)).orderByTaskCreateTime().desc()
                                            .list();

        Map<String, Map<String, List<String>>> activeTaskUserMap = activeTasks.stream().collect(Collectors.toMap(Task::getId, task -> {
            List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(task.getId());
            List<String> users = new ArrayList<>();
            List<String> roles = new ArrayList<>();
            List<String> orgs = new ArrayList<>();
            identityLinks.forEach(identityLink -> {
                if (IdentityLinkType.CANDIDATE.equals(identityLink.getType())) {
                    if (StringUtils.isNotBlank(identityLink.getUserId())) {
                        userIds.add(identityLink.getUserId());
                        users.add(identityLink.getUserId());
                    } else if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                        String group = identityLink.getGroupId();
                        String[] groupArr = group.split(":");
                        String type = groupArr[0], id = groupArr[1];
                        if ("ROLE".equals(type)) {
                            roleIds.add(Long.parseLong(id));
                            roles.add(id);
                        } else if ("ORG".equals(type)) {
                            orgIds.add(Long.parseLong(id));
                            orgs.add(id);
                        }
                    }
                }
            });
            Map<String, List<String>> map = new HashMap<>();
            map.put("users", users);
            map.put("roles", roles);
            map.put("orgs", orgs);
            return map;

        }));
        
        /*List<String> nextUserIds = activeTasks.stream().filter(activeTask->StringUtils.isNotBlank(activeTask.getAssignee())).map
        (Task::getAssignee).collect(Collectors.toList());
        userIds.addAll(nextUserIds);*/

        Map<String, SecUser> userMap = queryUsersForMap(userIds);
        Map<String, SecRole> roleMap = queryRolesForMap(roleIds);
        Map<String, SecInstitution> orgMap = queryOrgsForMap(orgIds);
        List<ViewProcessTask> viewProcessTasks = tasks.stream().map(taskInstance -> {
            HistoricProcessInstance processInstance = procMap.get(taskInstance.getProcessInstanceId());
            ViewProcessTask task = hisTaskToViewTask(processInstance, taskInstance, userMap);
            task.setFormKey(getCustomForm(taskInstance, processInstance.getBusinessKey(), null, false));
            List<TaskComment> comments = taskCommentMap.get(task.getTaskId());
            if (Objects.nonNull(comments) && comments.size() > 0) {
                task.setComments(comments);
                task.setComment(comments.get(0).getComment());
            }
            return task;
        }).collect(Collectors.toList());

        List<ViewProcessTask> nextProcessTasks = activeTasks.stream().map(activeTask -> {
            HistoricProcessInstance processInstance = procMap.get(activeTask.getProcessInstanceId());
            ViewProcessTask task = taskToViewTask(processInstance, activeTask, userMap);
            task.setFormKey(getCustomForm(activeTask, processInstance.getBusinessKey(), null, false));
            Map<String, List<String>> userInfoMap = activeTaskUserMap.get(activeTask.getId());
            //将原来的users重命名成usersAll，下面去重后命名成users
            List<String> usersAll = userInfoMap.get("users");
            //对查出的人员去重
            List<String> users = usersAll.stream().distinct().collect(Collectors.toList());
            List<String> roles = userInfoMap.get("roles");
            List<String> orgs = userInfoMap.get("orgs");
            if (CollectionUtils.isNotEmpty(users)) {
                task.setNextAssignee(StringUtils.join(users, ","));
                List<String> names = users.stream().map(user -> {
                    SecUser secUser = userMap.get(user);
                    return StringUtils.isBlank(secUser.getRealName()) ? secUser.getUsername() : secUser.getRealName();
                }).collect(Collectors.toList());
                task.setNextAssigneeName(StringUtils.join(names, ","));
            }
            if (CollectionUtils.isNotEmpty(roles)) {
                task.setNextRole(StringUtils.join(roles, ","));
                List<String> names = roles.stream().map(role -> {
                    SecRole secRole = roleMap.get(role);
                    return secRole.getName();
                }).collect(Collectors.toList());
                task.setNextRoleName(StringUtils.join(names, ","));
            }

            if (CollectionUtils.isNotEmpty(orgs)) {
                task.setNextOrg(StringUtils.join(orgs, ","));
                List<String> names = orgs.stream().map(org -> {
                    SecInstitution secOrg = orgMap.get(org);
                    return secOrg.getName();
                }).collect(Collectors.toList());
                task.setNextOrgName(StringUtils.join(names, ","));
            }
            String nextText = "";
            if (StringUtils.isNotBlank(task.getNextAssignee())) {
                nextText += task.getNextAssigneeName();
            }

            if (StringUtils.isNotBlank(task.getNextRole())) {
                nextText += "【角色:" + task.getNextRoleName() + "】";
            }

            if (StringUtils.isNotBlank(task.getNextOrg())) {
                nextText += "【部门:" + task.getNextOrgName() + "】";
            }
            task.setNextText(nextText);
            return task;
        }).collect(Collectors.toList());
        nextProcessTasks.addAll(viewProcessTasks);
        //已处理环节和未处理环节单独查询的，由于数据量较小，所以查询出结果以后再分页
        int size = nextProcessTasks.size();
        int current = pager.getCurrent();
        int pageSize = pager.getPageSize();
        int listNum = current * pageSize;
        int beginNum = (current - 1) * pageSize;
        if (size < beginNum) {
        } else if (size >= listNum) {
            nextProcessTasks = nextProcessTasks.subList(beginNum, listNum);
        } else {
            nextProcessTasks = nextProcessTasks.subList(beginNum, size);
        }
        pager.setTotalCount(size);
        pager.setTotalPageCount((long) Math.ceil((float) size / pageSize));
        return nextProcessTasks;
    }

    private Map<String, SecRole> queryRolesForMap(Set<Long> roleIds) {
        if (roleIds.isEmpty()) {
            return null;
        }
        return roleService.queryRoles(roleIds).stream().collect(Collectors.toMap(role -> role.getId().toString(), task -> task));
    }

    private Map<String, SecInstitution> queryOrgsForMap(Set<Long> orgsIds) {
        if (orgsIds.isEmpty()) {
            return null;
        }
        return institutionService.queryInstitutions(orgsIds).stream().collect(Collectors.toMap(org -> org.getId().toString(), org -> org));
    }

    private ViewProcessTask taskToViewTask(HistoricProcessInstance processInstance, TaskInfo task, Map<String, SecUser> userMap) {
        ViewProcessTask view = new ViewProcessTask();
        view.setName(task.getName());
        view.setAssignee(task.getAssignee());
        view.setSn(processInstance.getSn());
        if (Objects.nonNull(userMap)) {
            SecUser assignee = userMap.get(task.getAssignee());
            SecUser startUser = userMap.get(processInstance.getStartUserId());
            if (Objects.nonNull(assignee)) {
                view.setAssigneeName(personName(assignee));
            }
            if (Objects.nonNull(startUser)) {
                view.setStartUserName(personName(startUser));
            }
        }
        view.setBusinessKey(processInstance.getBusinessKey());
        view.setFormKey(task.getFormKey());
        view.setCreateTime(JGPUtil.dateToLocalDateTime(task.getCreateTime()).format(JGPUtil.DATE_TIME_FORMATTER));
        view.setProcId(task.getProcessInstanceId());
        view.setProcName(processInstance.getProcessDefinitionName());
        view.setTaskId(task.getId());
        view.setStartUser(processInstance.getStartUserId());
        view.setOwner(task.getOwner());
        view.setPriority(task.getPriority() + "");
        view.setTaskDefinitionKey(task.getTaskDefinitionKey());
        return view;
    }

    private ViewProcessTask hisTaskToViewTask(HistoricProcessInstance processInstance, HistoricTaskInstance task, Map<String, SecUser> userMap) {
        ViewProcessTask view = taskToViewTask(processInstance, (TaskInfo) task, userMap);
        view.setEndTime(JGPUtil.dateToLocalDateTime(task.getEndTime()).format(JGPUtil.DATE_TIME_FORMATTER));
        return view;
    }

    private String personName(SecUser user) {
        return StringUtils.isNotBlank(user.getRealName()) ? user.getRealName() : user.getUsername();
    }

    @Override
    public List<ViewProcessIns> queryWorkOrder(QueryWorkOrderForm queryForm, Pager pager) {
        UserInfo userInfo = userAdapter.currentUser();
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        if (StringUtils.isNotBlank(queryForm.getGroupType())) {
            switch (queryForm.getGroupType()) {
                //指定用户发起的
                case "1":
                    query.startedBy(queryForm.getUserId());
                    break;
                //指定用户审批的
                case "2":
                    //查询出所有的指定用户参与审批的历史任务
                    List<HistoricTaskInstance> allApprovalTasks = historyService.createHistoricTaskInstanceQuery().taskAssignee(queryForm.getUserId())
                                                                                .list();
                    //过滤出所有的指定用户参与审批的流程实例ID
                    Set<String> allApprovalProcIds = allApprovalTasks.stream().map(HistoricTaskInstance::getProcessInstanceId).distinct()
                                                                     .collect(Collectors.toSet());
                    if (allApprovalProcIds.size() == 0) return null;
                    query.processInstanceIds(allApprovalProcIds);
                    break;
                //指定用户部门审批的
                case "3":
                    //查询指定用户所在部门ID集合
                    List<SecInstitution> institutions = userInfo.getInstitutions();
                    institutions.addAll(institutionService.queryDown(institutions));
                    if (Objects.isNull(institutions) || institutions.size() == 0) return null;
                    List<String> groupIds = institutions.stream().map(org -> "ORG:" + org.getId()).distinct().collect(Collectors.toList());
                    List<String> groups = new ArrayList<>();
                    groupIds.forEach(groupId -> {
                        groups.add("R:" + groupId);
                    });
                    groups.addAll(groupIds);
                    //查询出所有的指定用户所在部门参与审批的历史任务
                    List<HistoricTaskInstance> allGroupApprovalTasks = historyService.createHistoricTaskInstanceQuery().taskCandidateGroupIn(groups)
                                                                                     .list();
                    //过滤出所有的指定用户参与审批的流程实例ID
                    Set<String> allGroupApprovalProcIds = allGroupApprovalTasks.stream().map(HistoricTaskInstance::getProcessInstanceId)
                                                                               .collect(Collectors.toSet());
                    if (allGroupApprovalProcIds.size() > 0) query.processInstanceIds(allGroupApprovalProcIds);
                    break;
            }

        } else {
            return null;
        }
        if (StringUtils.isNotBlank(queryForm.getName())) {
            query.processInstanceNameLikeIgnoreCase("%" + queryForm.getName() + "%");
        }
        if (StringUtils.isNotBlank(queryForm.getSn())) {
            query.processInstanceSn(queryForm.getSn());
        }
        if (StringUtils.isNotBlank(queryForm.getCategory())) {
            query.processDefinitionCategory(queryForm.getCategory());
        }
        //申请时间 <
        if (StringUtils.isNotBlank(queryForm.getApplyTimeBegin())) {
            query.startedAfter(dateStrToBeginTime(queryForm.getApplyTimeBegin()));
        }
        //申请时间 >
        if (StringUtils.isNotBlank(queryForm.getApplyTimeOver())) {
            query.startedBefore(dateStrToEndTime(queryForm.getApplyTimeOver()));
        }
        //完成时间 <
        if (StringUtils.isNotBlank(queryForm.getEndTimeBegin())) {
            query.finishedAfter(dateStrToBeginTime(queryForm.getEndTimeBegin()));
        }
        //申请时间 >
        if (StringUtils.isNotBlank(queryForm.getEndTimeOver())) {
            query.finishedBefore(dateStrToEndTime(queryForm.getEndTimeOver()));
        }

        if (StringUtils.isNotBlank(queryForm.getStatus())) {
            switch (queryForm.getStatus()) {
                case "1":
                    query.notDeleted().unfinished();
                    break;
                case "2":
                    query.notDeleted().finished();
                    break;
                case "3":
                    query.deleted();
                    break;
            }
        }
        query.orderByProcessInstanceStartTime().desc();
        //工单管理分页查询
        long count = query.count();
        pager.setTotalCount(count);
        List<HistoricProcessInstance> processInstances = query.listPage((pager.getCurrent() - 1) * pager.getPageSize(), pager.getPageSize());
        int i = (int) (count+pager.getPageSize()-1) / pager.getPageSize();
        pager.setTotalPageCount(i);
        List<ViewProcessIns> list = processInstances.stream().map(processInstance -> hisInsToViewIns(processInstance)).collect(Collectors.toList());
        List<String> procIds = list.stream().map(ViewProcessIns::getId).collect(Collectors.toList());

        if (Objects.nonNull(procIds) && procIds.size() > 0) {
            Map<String, Boolean> states = queryProcApplyState(procIds);
            list.forEach(proc -> {
                proc.setApplyNode(states.get(proc.getId()));
            });
        }
        Map<String, Object> variableMap = new HashMap<>();

        //查询工单内容
        Set<String> pIds = list.stream().map(ViewProcessIns::getId).collect(Collectors.toSet());
        if (Objects.nonNull(pIds) && pIds.size() > 0) {
            List<ProcVar> procVars = managementService.executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<ProcVar>>(TaskMapper.class) {
                @Override
                public List<ProcVar> execute(TaskMapper taskMapper) {
                    return taskMapper.getProcVar(pIds, "orderContent");
                }
            });
            procVars.forEach(procVar -> {
                if (procVar.getType().equals("string")) {
                    variableMap.put(procVar.getProcId(), procVar.getTextValue());
                }
            });
        }
        if (Objects.nonNull(procIds) && procIds.size() > 0) {
            list.forEach(proc -> {
                String orderContent = (String) variableMap.get(proc.getId());
                proc.setOrderContent(orderContent);
            });
        }
        return list.stream().collect(Collectors.toList());
    }

    /**
     * 查询指定流程实例是否在申请节点处
     *
     * @param procIds
     * @return
     */
    private Map<String, Boolean> queryProcApplyState(List<String> procIds) {
        Map<String, Boolean> result = new HashMap<>();
        List<ProcApplyState> list = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<ProcApplyState>>(TaskMapper.class) {
                    @Override
                    public List<ProcApplyState> execute(TaskMapper taskMapper) {
                        return taskMapper.queryProcApplyState(procIds);
                    }
                });

        list.forEach(map -> {
            result.put(map.getProcId(), map.getApplyNode());
        });
        return result;
    }

    private Date dateStrToBeginTime(String date) {
        return JGPUtil.localDateTimeToDate(JGPUtil.startOfDate(LocalDate.parse(date, JGPUtil.DATE_FORMATTER)));
    }

    private Date dateStrToEndTime(String date) {
        return JGPUtil.localDateTimeToDate(JGPUtil.endOfDate(LocalDate.parse(date, JGPUtil.DATE_FORMATTER)));
    }

    @Override
    public List<ViewProcessDef> queryAllProcessDef(Pager pager) {
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();

        Long count = query.count();
        List<ProcessDefinition> processDefinitions = query.latestVersion().orderByProcessDefinitionCategory().desc().orderByProcessDefinitionVersion()
                                                          .desc().listPage((pager.getCurrent() - 1) * pager.getPageSize(), pager.getPageSize());
        pager.setTotalCount(count);
        float per = count % pager.getPageSize();
        pager.setTotalPageCount(per != 0 ? (count / pager.getPageSize() + 1) : count / pager.getPageSize());

        List<ViewProcessDef> processDefs = new ArrayList<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            ProcessDefinitionEntity pe = (ProcessDefinitionEntity) processDefinition;
            ViewProcessDef processDef = new ViewProcessDef();
            processDef.setCategory(pe.getCategory());
            processDef.setDefKey(pe.getKey());
            processDef.setVersion(pe.getVersion() + "");
            processDef.setDefName(pe.getName());
            processDefs.add(processDef);
        }
        return processDefs;
    }

    @Override
    public String getCustomForm(String procId, String taskId, String userId, Boolean editFlag) {
        if (Objects.isNull(taskId)) {
            Task task = taskService.createTaskQuery().processInstanceId(procId).taskUnassigned().active().singleResult();
            if (Objects.nonNull(task)) taskId = task.getId();
        }
        if (Objects.isNull(taskId)) return null;
        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().processInstanceId(procId).taskId(taskId).singleResult();
        HistoricProcessInstance process = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();

        String businessKey = process.getBusinessKey();

        return getCustomForm(task, businessKey, userId, editFlag);
    }

    private String getCustomForm(TaskInfo task, String businessKey, String userId, Boolean editFlag) {
        //抽回或者作废的工单，任务处理的时候进行提示，对task进行判空操作
        if(Objects.nonNull(task)){
            String formKey = formService.getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
            if (StringUtils.isBlank(formKey)) formKey = "/workflow/processController/showDefaultTaskForm";
            String url = formKey + "?businessKey=" + businessKey + "&procId=" + task.getProcessInstanceId() + "&taskId=" + task.getId();
            if (StringUtils.isNotBlank(userId)) url += "&userId=" + userId + "&editFlag=" + editFlag;
            if (Objects.nonNull(task.getAssignee())) {
                if (task.getAssignee().equals(userId)) {
                    url += "&claimState=self";
                } else {
                    url += "&claimState=other";
                }
            }
            return url;
        }else{
            return null;
        }
    }

    @Override
    public ViewProcessIns queryOneProcessIns(String procId) {
        HistoricProcessInstance hisInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        return hisInsToViewIns(hisInstance);
    }

    @Override
    public ViewProcessIns queryOneProcessInsBySn(String sn) {
        HistoricProcessInstance hisInstance = historyService.createHistoricProcessInstanceQuery().processInstanceSn(sn).singleResult();
        return hisInsToViewIns(hisInstance);
    }

    private ViewProcessIns hisInsToViewIns(HistoricProcessInstance historicProcessInstance) {
        ViewProcessIns instance = new ViewProcessIns();
        instance.setName(historicProcessInstance.getProcessDefinitionName());
        instance.setCreateTime(JGPUtil.dateToLocalDateTime(historicProcessInstance.getStartTime()));
        instance.setCompleteTime(JGPUtil.dateToLocalDateTime(historicProcessInstance.getEndTime()));
        instance.setId(historicProcessInstance.getId());
        instance.setSn(historicProcessInstance.getSn());
        SecUser user = userService.query(historicProcessInstance.getStartUserId());
        instance.setSecUser(user);
        return instance;
    }

    @Override
    public List<TreeBean> queryTasksByProcForTree(String procId) {
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().processInstanceId(procId);
        List<HistoricTaskInstance> tasks = query.orderByTaskCreateTime().asc().list();
        HistoricProcessInstance process = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        List<String> assigneeIds = tasks.stream().map(HistoricTaskInstance::getAssignee).collect(Collectors.toList());
        assigneeIds.add(process.getStartUserId());
        Map<String, SecUser> userMap = queryUsersForMap(assigneeIds);
        tasks = tasks.stream().sorted(Comparator.comparing(HistoricTaskInstance::getStartTime).reversed()).collect(Collectors.toList());
        Map<String, List<TaskComment>> taskCommentMap = taskCommentMap(tasks);
        AtomicInteger index = new AtomicInteger();
        List<TreeBean> result = tasks.stream().map(taskInstance -> {
            TreeBean treeBean = new TreeBean();
            treeBean.setKey(taskInstance.getId());
            treeBean.setTitle(taskInstance.getName());
            ViewProcessTask task = taskToViewTask(process, taskInstance, userMap);
            /*if(index.get() == finalTasks.size()-1){
                task.setStartUser(process.getStartUserId());
                SecUser user = assignees.get(process.getStartUserId());
                task.setAssigneeName(StringUtils.isNotBlank(user.getRealName())?user.getRealName():user.getUsername());
            }*/
            task.setComments(taskCommentMap.get(task.getTaskId()));
            Map<String, Object> beanMap = JGPUtil.toMap(task);
            beanMap.put("formKey", getCustomForm(taskInstance, process.getBusinessKey(), null, false));
            treeBean.setBean(beanMap);
            index.getAndIncrement();
            return treeBean;
        }).collect(Collectors.toList());
        result.remove(0);
        return result;
    }

    @Override
    public List<String> queryRunTimeBusinessKeyByTaskDefIdAndProcDefId(String procDefKey, String taskDefKey) {
        List<Task> tasks = taskService.createTaskQuery().processDefinitionId(procDefKey).taskDefinitionKey(taskDefKey).list();
        if (Objects.isNull(tasks) || tasks.size() == 0) return null;
        Set<String> instanceIds = tasks.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
        List<ProcessInstance> instances = runtimeService.createProcessInstanceQuery().processInstanceIds(instanceIds).list();
        if (Objects.isNull(instances) || instances.size() == 0) return null;
        return instances.stream().map(ProcessInstance::getBusinessKey).collect(Collectors.toList());
    }

    @Override
    public List<ViewProcessTask> queryActiveTasksByUserAndTaskDefKey(String userId, String procId, String taskDefKey) {
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().unfinished().processInstanceId(procId)
                                                        .taskDefinitionKey(taskDefKey);
        query.or().taskCandidateUser(userId).taskAssignee(userId).endOr();
        List<HistoricTaskInstance> tasks = query.list();

        return taskToViewTasks(procId, tasks, null);

    }


    private List<ViewProcessTask> taskToViewTasks(String procId, List<HistoricTaskInstance> tasks, Map<String, SecUser> userMap) {
        if (Objects.nonNull(tasks) && tasks.size() > 0) {
            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
            return tasks.stream().map(taskInfo -> taskToViewTask(processInstance, taskInfo, userMap)).collect(Collectors.toList());
        } else {
            return null;
        }

    }

    @Override
    public List<ViewProcessTask> queryActiveTasksByUserAndTaskDefKey(List<Long> roleIds, List<Long> orgIds, String procId, String taskDefKey) {
        List<String> groups = new ArrayList<>();
        if (Objects.nonNull(roleIds)) {
            groups.addAll(roleIds.stream().map(id -> "ROLE:" + id).collect(Collectors.toList()));
        }

        if (Objects.nonNull(orgIds)) {
            groups.addAll(orgIds.stream().map(id -> "ORG:" + id).collect(Collectors.toList()));
        }
        if (groups.size() == 0) return null;

        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().unfinished().processInstanceId(procId)
                                                        .taskDefinitionKey(taskDefKey).taskCandidateGroupIn(groups);
        List<HistoricTaskInstance> tasks = query.list();
        return taskToViewTasks(procId, tasks, null);
    }

    @Transactional
    @Override
    public void claim(String userId, String taskId, String remark) throws WorkflowException {
        Assert.notNull(userId, "用户Id不能为空！");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String procId = task.getProcessInstanceId();
        try {
            taskService.claim(taskId, userId);
        } catch (ActivitiObjectNotFoundException e) {
            throw new WorkflowException(WorkflowErrorCode.TASK_NOT_FOUND);
        } catch (ActivitiTaskAlreadyClaimedException e) {
            throw new WorkflowException(WorkflowErrorCode.TASK_ALREADY_CLAIMED);
        }

        if (StringUtils.isNotBlank(remark)) {
            taskService.addComment(taskId, procId, remark);
        }
    }

    @Transactional
    @Override
    public void unClaim(String userId, String taskId, String remark) throws WorkflowException {
        Assert.notNull(userId, "用户Id不能为空！");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String procId = task.getProcessInstanceId();
        try {
            taskService.unclaim(taskId);
        } catch (ActivitiObjectNotFoundException e) {
            throw new WorkflowException(WorkflowErrorCode.TASK_NOT_FOUND);
        } catch (ActivitiTaskAlreadyClaimedException e) {
            throw new WorkflowException(WorkflowErrorCode.TASK_ALREADY_CLAIMED);
        }

        if (StringUtils.isNotBlank(remark)) {
            taskService.addComment(taskId, procId, remark);
        }
    }

    @Override
    public List<TaskComment> queryTaskComments(String taskId) {
        List<String> taskIds = new ArrayList<>();
        taskIds.add(taskId);

        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        com.jgp.security.secmodel.SecUser user = null;
        if (StringUtils.isNotBlank(task.getAssignee())) {
            user = userService.query(task.getAssignee());
        }
        if (Objects.isNull(user) && StringUtils.isNotBlank(task.getAssignee()) && task.getAssignee().equals(userService.getSuperAdmin().getId())) {
            user = userService.getSuperAdmin();
        }
        List<TaskComment> comments = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<TaskComment>>(TaskMapper.class) {
                    @Override
                    public List<TaskComment> execute(TaskMapper taskMapper) {
                        return taskMapper.queryTaskComments(taskIds);
                    }
                });
        for (TaskComment comment : comments) {
            comment.setUserName(Objects.nonNull(user) && Objects.nonNull(user.getRealName()) ? user.getRealName() : user.getUsername());
        }
        return comments;
    }

    @Override
    public List<TaskComment> queryTaskComments(String procId, String taskDefKey) {

        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskDefinitionKey(taskDefKey).singleResult();
        com.jgp.security.secmodel.SecUser user = null;
        if (StringUtils.isNotBlank(task.getAssignee())) {
            user = userService.query(task.getAssignee());
        }
        List<TaskComment> comments = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<TaskComment>>(TaskMapper.class) {
                    @Override
                    public List<TaskComment> execute(TaskMapper taskMapper) {
                        return taskMapper.queryTaskComments2(procId, task.getId());
                    }
                });
        for (TaskComment comment : comments) {
            comment.setUserName(Objects.nonNull(user) && Objects.nonNull(user.getRealName()) ? user.getRealName() : user.getUsername());
        }
        return comments;
    }

    @Override
    public TaskComment queryLastTaskComments(String taskId) {
        return queryTaskComments(taskId).stream().max(Comparator.comparing(TaskComment::getTime)).get();
    }

    @Override
    public TaskComment queryLastTaskCommentByProcIdAndTaskDefkey(String procId, String taskDefKey) {
        return queryTaskComments(procId, taskDefKey).stream().max(Comparator.comparing(TaskComment::getTime)).get();
    }
    
    @Override
    public List<TaskComment> queryAllCommentByProcId(String procId) {
        List<TaskComment> comments = managementService
                .executeCustomSql(new AbstractCustomSqlExecution<TaskMapper, List<TaskComment>>(TaskMapper.class) {
                    @Override
                    public List<TaskComment> execute(TaskMapper taskMapper) {
                        return taskMapper.queryProcInsComments(procId);
                    }
                });
        List<String> userIds = comments.stream().map((comment)->{
            return comment.getUserId();
        }).collect(Collectors.toList());
        
        List<SecUser> users = userService.query(userIds);
        Map<String,String> userMap = users.stream().collect(Collectors.toMap(SecUser::getId, SecUser::getRealName));
        for (TaskComment comment : comments) {
            comment.setUserName(userMap.get(comment.getUserId()));
        }
        return comments;
    }
    
    private List<String> queryTasksAssigneeIds(String procId, String taskDefKey) {
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().processInstanceId(procId).taskDefinitionKey(taskDefKey);

        List<HistoricTaskInstance> tasks = query.list();
        return tasks.stream().map(HistoricTaskInstance::getAssignee).distinct().collect(Collectors.toList());
    }

    @Override
    public List<SecUser> queryTasksAssignees(String procId, String taskDefKey) {
        List<SecUser> users = userService.query(queryTasksAssigneeIds(procId, taskDefKey));
        return users;
    }

    @Override
    public List<SecUser> queryTasksAssignees(String procId, List<String> taskDefKeys) {
        List<String> assignees = new ArrayList<>();
        taskDefKeys.forEach(key -> {
            List<String> assignees_key = queryTasksAssigneeIds(procId, key);
            if (Objects.nonNull(assignees_key) && assignees_key.size() > 0) {
                assignees.addAll(assignees_key);
            }
        });
        List<String> assigneeIds = assignees.stream().distinct().collect(Collectors.toList());
        List<SecUser> users = userService.query(assigneeIds);
        return users;
    }

    @Transactional
    @Override
    public void removeProcIns(String procId, String reason) {
        runtimeService.deleteProcessInstance(procId, reason);
        historyService.createHistoricTaskInstanceQuery().processInstanceId(procId).list().forEach(historicTaskInstance -> {
            historyService.deleteHistoricTaskInstance(historicTaskInstance.getId());
        });
        historyService.deleteHistoricProcessInstance(procId);
    }

    @Override
    public List<ViewProcessIns> queryProcessIns(List<String> businessKeys) {
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        List<ViewProcessIns> ins = new ArrayList<>();

        businessKeys.forEach(key -> {
            query.processInstanceBusinessKey(key);
            HistoricProcessInstance instance = query.singleResult();
            if (Objects.isNull(instance)) return;
            ViewProcessIns viewProcessIns = hisInsToViewIns(instance);

            if (Objects.isNull(instance.getEndTime())) {
                viewProcessIns.setStatus(ProcessStatus.ING);
            } else if (StringUtils.isBlank(instance.getDeleteReason())) {
                viewProcessIns.setStatus(ProcessStatus.DEL);
            } else {
                viewProcessIns.setStatus(ProcessStatus.OVER);
            }
            ins.add(viewProcessIns);
        });
        return ins;
    }

    @Override
    public ViewProcessIns queryOneProcessInsByBusinessKey(String businessKey) {
        HistoricProcessInstance hisInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey)
                                                            .singleResult();
        return hisInsToViewIns(hisInstance);
    }

    private void complete(String userId, String procId, String taskId, String remark, Map<String, Object> variables, Boolean localScope) throws WorkflowException {

        //priority

        //Assert.notNull(userId, "用户Id不能为空！");
        Assert.notNull(procId, "流程实例Id不能为空！");
        if (StringUtils.isBlank(taskId)) {
            HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().processInstanceId(procId);
            Long taskCount = query.count();
            if (taskCount == 0) {
                logger.info("无效流程");
                throw new WorkflowException(WorkflowErrorCode.PROC_INVALID);
            } else if (taskCount == 1) {
                HistoricTaskInstance task = query.singleResult();
                taskId = task.getId();
            } else {
                logger.info("流程已经启动");
                throw new WorkflowException(WorkflowErrorCode.PROC_START_FAIL);
            }
        }

        if (StringUtils.isNotBlank(userId)) {
            try {
                //taskService.claim(taskId, userId);
                taskService.setAssignee(taskId, userId);
            } catch (ActivitiObjectNotFoundException e) {
                throw new WorkflowException(WorkflowErrorCode.TASK_NOT_FOUND);
            } catch (ActivitiTaskAlreadyClaimedException e) {
                throw new WorkflowException(WorkflowErrorCode.TASK_ALREADY_CLAIMED);
            }
        }

        if (StringUtils.isNotBlank(remark)) {
            Authentication.setAuthenticatedUserId(userId);
            taskService.addComment(taskId, procId, remark);
        }

        localScope = Objects.isNull(localScope) ? false : localScope;
        if (Objects.nonNull(variables) && variables.size() > 0) {
            taskService.complete(taskId, variables, localScope);
        } else {
            taskService.complete(taskId);
        }

        Object priority = Objects.nonNull(variables) ? variables.get("priority") : null;

        HistoricVariableInstance priorityInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId)
                                                                  .variableName("priority").singleResult();

        if (Objects.nonNull(priority) && Objects.nonNull(priorityInstance) && !priority.equals(priorityInstance.getValue())) {
            if ("100".equals(priority)) {
                makeTop(procId);
            } else {
                makeUnTop(procId);
            }
        }

        List<ViewProcessTask> activeTasks = getActiveTask(procId);
        if (Objects.nonNull(activeTasks) && Objects.isNull(priority) && Objects.nonNull(priorityInstance) && Objects
                .nonNull(priorityInstance.getValue())) {
            activeTasks.forEach(activeTask -> {
                taskService.setPriority(activeTask.getTaskId(), Integer.parseInt(priorityInstance.getValue().toString()));
            });
        }
    }

    @Override
    public void makeTop(String procId) {
        taskService.createTaskQuery().processInstanceId(procId).taskPriority(50).list().stream().forEach(task -> {
            //task.setPriority(100);
            taskService.setPriority(task.getId(), 100);
        });
        runtimeService.setVariable(procId, "priority", 100);
    }

    @Override
    public void makeUnTop(String procId) {
        taskService.createTaskQuery().processInstanceId(procId).taskPriority(100).list().stream().forEach(task -> {
            taskService.setPriority(task.getId(), 50);
        });
        runtimeService.setVariable(procId, "priority", 50);
    }
    @Override
    public List<ViewProcessTask> queryProcessTaskAssignee(String procId) {
        HistoricTaskInstanceQuery query = (HistoricTaskInstanceQuery)this.historyService.createHistoricTaskInstanceQuery().finished().processInstanceId(procId);
        List<HistoricTaskInstance> tasks = ((HistoricTaskInstanceQuery)((HistoricTaskInstanceQuery)query.orderByTaskCreateTime()).desc()).list();
        Set<String> procIds = (Set)tasks.stream().map(TaskInfo::getProcessInstanceId).collect(Collectors.toSet());
        if (!Objects.isNull(procIds) && procIds.size() != 0) {
            List<HistoricProcessInstance> processInstances = this.historyService.createHistoricProcessInstanceQuery().processInstanceIds(procIds).list();
            List<String> userIds = (List)tasks.stream().map(TaskInfo::getAssignee).collect(Collectors.toList());
            Map<String, HistoricProcessInstance> procMap = new HashMap();
            processInstances.forEach((processIns) -> {
                procMap.put(processIns.getId(), processIns);
                userIds.add(processIns.getStartUserId());
            });
            Map<String, List<TaskComment>> taskCommentMap = this.taskCommentMap(tasks);
            Set<Long> roleIds = new HashSet();
            Set<Long> orgIds = new HashSet();
            List<Task> activeTasks = ((TaskQuery)((TaskQuery)((TaskQuery)this.taskService.createTaskQuery().active().processInstanceIdIn(new ArrayList(procIds))).orderByTaskCreateTime()).desc()).list();
            Map<String, Map<String, List<String>>> activeTaskUserMap = (Map)activeTasks.stream().collect(Collectors.toMap(TaskInfo::getId, (task) -> {
                List<IdentityLink> identityLinks = this.taskService.getIdentityLinksForTask(task.getId());
                List<String> users = new ArrayList();
                List<String> roles = new ArrayList();
                List<String> orgs = new ArrayList();
                identityLinks.forEach((identityLink) -> {
                    if ("candidate".equals(identityLink.getType())) {
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            userIds.add(identityLink.getUserId());
                            users.add(identityLink.getUserId());
                        } else if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            String group = identityLink.getGroupId();
                            String[] groupArr = group.split(":");
                            String type = groupArr[0];
                            String id = groupArr[1];
                            if ("ROLE".equals(type)) {
                                roleIds.add(Long.parseLong(id));
                                roles.add(id);
                            } else if ("ORG".equals(type)) {
                                orgIds.add(Long.parseLong(id));
                                orgs.add(id);
                            }
                        }
                    }

                });
                Map<String, List<String>> map = new HashMap();
                map.put("users", users);
                map.put("roles", roles);
                map.put("orgs", orgs);
                return map;
            }));
            Map<String, SecUser> userMap = this.queryUsersForMap(userIds);
            Map<String, SecRole> roleMap = this.queryRolesForMap(roleIds);
            Map<String, SecInstitution> orgMap = this.queryOrgsForMap(orgIds);
            List viewProcessTasks = (List)tasks.stream().map((taskInstance) -> {
                HistoricProcessInstance processInstance = (HistoricProcessInstance)procMap.get(taskInstance.getProcessInstanceId());
                ViewProcessTask task = this.hisTaskToViewTask(processInstance, taskInstance, userMap);
                return task;
            }).collect(Collectors.toList());
            List nextProcessTasks = (List)activeTasks.stream().map((activeTask) -> {
                HistoricProcessInstance processInstance = (HistoricProcessInstance)procMap.get(activeTask.getProcessInstanceId());
                ViewProcessTask task = this.taskToViewTask(processInstance, activeTask, userMap);
                Map<String, List<String>> userInfoMap = (Map)activeTaskUserMap.get(activeTask.getId());
                List<String> usersAll = (List)userInfoMap.get("users");
                List<String> users = (List)usersAll.stream().distinct().collect(Collectors.toList());
                List<String> roles = (List)userInfoMap.get("roles");
                List<String> orgs = (List)userInfoMap.get("orgs");
                List names;
                if (CollectionUtils.isNotEmpty(users)) {
                    task.setNextAssignee(StringUtils.join(users, ","));
                    names = (List)users.stream().map((user) -> {
                        SecUser secUser = (SecUser)userMap.get(user);
                        return StringUtils.isBlank(secUser.getRealName()) ? secUser.getUsername() : secUser.getRealName();
                    }).collect(Collectors.toList());
                    task.setNextAssigneeName(StringUtils.join(names, ","));
                }

                if (CollectionUtils.isNotEmpty(roles)) {
                    task.setNextRole(StringUtils.join(roles, ","));
                    names = (List)roles.stream().map((role) -> {
                        SecRole secRole = (SecRole)roleMap.get(role);
                        return secRole.getName();
                    }).collect(Collectors.toList());
                    task.setNextRoleName(StringUtils.join(names, ","));
                }

                if (CollectionUtils.isNotEmpty(orgs)) {
                    task.setNextOrg(StringUtils.join(orgs, ","));
                    names = (List)orgs.stream().map((org) -> {
                        SecInstitution secOrg = (SecInstitution)orgMap.get(org);
                        return secOrg.getName();
                    }).collect(Collectors.toList());
                    task.setNextOrgName(StringUtils.join(names, ","));
                }

                String nextText = "";
                if (StringUtils.isNotBlank(task.getNextAssignee())) {
                    nextText = nextText + task.getNextAssigneeName();
                }

                if (StringUtils.isNotBlank(task.getNextRole())) {
                    nextText = nextText + "【角色:" + task.getNextRoleName() + "】";
                }

                if (StringUtils.isNotBlank(task.getNextOrg())) {
                    nextText = nextText + "【部门:" + task.getNextOrgName() + "】";
                }

                task.setNextText(nextText);
                return task;
            }).collect(Collectors.toList());
            nextProcessTasks.addAll(viewProcessTasks);
            return nextProcessTasks;
        } else {
            return null;
        }
    }
}
